// in nodejs,can use require instead of import
// in front-end javascript, cannot use require, can only use import
import { contractABI, contractAddress } from "./constants.js"

// const { ethers } = require("ethers")
import { ethers } from "./ethers-6.7.0.min.js"
// import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"

const connectButton = document.getElementById("connectButton")
const fundButton = document.getElementById("fundButton")
const withdrawButton = document.getElementById("withdrawButton")
const balanceButton = document.getElementById("balanceButton")
connectButton.onclick = connect
fundButton.onclick = fund
withdrawButton.onclick = withdraw
balanceButton.onclick = getBalance

async function connect() {
    if (typeof window.ethereum !== "undefined") {
        try {
            await window.ethereum.request({
                method: "eth_requestAccounts",
            })
        } catch (error) {
            console.error("Error connecting to MetaMask:", error)
        }

        connectButton.innerHTML = "Connected"
        connectButton.disabled = true
        const accounts = await window.ethereum.request({
            method: "eth_accounts",
        })
        console.log("Connected account:", accounts)
    } else {
        connectButton.innerHTML = "Please install MetaMask"
    }
}

// balance function
async function getBalance() {
    if (typeof window.ethereum !== "undefined") {
        // connection / provider to the blockchain
        const provider = new ethers.BrowserProvider(window.ethereum)
        // const provider = new ethers.providers.web3Provider(window.ethereum) // for ethers v5
        try {
            const singerAddress = await (
                await provider.getSigner()
            ).getAddress() // for ethers v6
            // const singerAddress = await provider.getSigner().getAddress() // for ethers v5
            console.log("Signer Address:", singerAddress)

            const network = await provider.getNetwork()
            console.log("Network:", network) // for ethers v6

            const balance = await provider.getBalance(contractAddress, "latest") // latest is the default block tag, block tags are "latest", "earliest", "pending", or a block number
            // const balance = await provider.getBalance(contractAddress) // for ethers v5
            console.log("Contract balance:", ethers.formatEther(balance)) // for ethers v6
            // console.log("Contract balance:", ethers.utils.formatEther(balance)) // for ethers v5
        } catch (error) {
            console.error("Error get balance:", error)
        }
    } else {
        connectButton.innerHTML = "Please install MetaMask"
    }
}

// fund function
async function fund() {
    const ethAmount = document.getElementById("ethAmount").value
    console.log("Funding with ETH amount:", ethAmount)

    if (typeof window.ethereum !== "undefined") {
        // connection / provider to the blockchain
        const provider = new ethers.BrowserProvider(window.ethereum)
        // signer / wallet / some account that can send a transaction
        const singer = await provider.getSigner()
        // contract that we are interacting with
        // ABI / Application Binary Interface, the interface of the contract
        // contract address / where the contract is deployed
        const contract = new ethers.Contract(
            contractAddress,
            contractABI,
            singer,
        )
        try {
            const transactionResponse = await contract.fund({
                value: ethers.parseEther(ethAmount), // for ethers v6
                // value: ethers.utils.parseEther(ethAmount), // for ethers v5
            })
            console.log("Funding transaction response:", transactionResponse)
            // await transactionResponse.wait(1);  // wait for 1 block confirmation
            // listen for the transaction to be mined
            await listenForTransactionMine(transactionResponse, provider) // wait for transaction to be mined
        } catch (error) {
            console.error("Error funding:", error)
        }
    } else {
        connectButton.innerHTML = "Please install MetaMask"
    }
}

// withdraw function
async function withdraw() {
    if (typeof window.ethereum !== "undefined") {
        const provider = new ethers.BrowserProvider(window.ethereum)
        await provider.send("eth_requestAccounts", [])
        const singer = await provider.getSigner() // ethers v6 must use await, because it returns a promise, but v5 returns a signer object directly
        const contract = new ethers.Contract(
            contractAddress,
            contractABI,
            singer,
        )
        try {
            const transactionResponse = await contract.withdraw()
            console.log("Withdraw transaction response:", transactionResponse)
            // await transactionResponse.wait(1);  // wait for 1 block confirmation
            await listenForTransactionMine(transactionResponse, provider) // wait for transaction to be mined
        } catch (error) {
            console.error("Error withdraw:", error)
        }
    } else {
        connectButton.innerHTML = "Please install MetaMask"
    }
}

function listenForTransactionMine(transactionResponse, provider) {
    console.log(`Mining ${transactionResponse.hash}`)

    return new Promise((resolve, reject) => {
        try {
            provider.once(transactionResponse.hash, (transactionReceipt) => {
                console.log(
                    `Completed with ${transactionReceipt.confirmations} confirmations. `,
                )
                resolve()
            })
        } catch (error) {
            reject(error)
        }
    })
}
